From 83956980907bcb886744b79209efce688f4cadf8 Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sun, 14 Jun 2020 05:30:06 +0200 Subject: [PATCH] selectionmodel: Replace query_range() with get_selection() --- docs/reference/gtk/gtk4-sections.txt | 3 +- gtk/gtkmultiselection.c | 18 ---- gtk/gtknoselection.c | 21 ++-- gtk/gtkpropertyselection.c | 38 +------ gtk/gtkselectionmodel.c | 148 +++++++++++++++------------ gtk/gtkselectionmodel.h | 38 ++++--- gtk/gtksingleselection.c | 62 +++-------- testsuite/gtk/singleselection.c | 46 +++++---- 8 files changed, 158 insertions(+), 216 deletions(-) diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt index 447e1c0d6c..3af8dbedeb 100644 --- a/docs/reference/gtk/gtk4-sections.txt +++ b/docs/reference/gtk/gtk4-sections.txt @@ -389,6 +389,8 @@ gtk_bitset_get_type GtkSelectionModel GtkSelectionModel gtk_selection_model_is_selected +gtk_selection_model_get_selection +gtk_selection_model_get_selection_in_range gtk_selection_model_select_item gtk_selection_model_unselect_item gtk_selection_model_select_range @@ -398,7 +400,6 @@ gtk_selection_model_unselect_all GtkSelectionCallback gtk_selection_model_select_callback gtk_selection_model_unselect_callback -gtk_selection_model_query_range gtk_selection_model_selection_changed diff --git a/gtk/gtkmultiselection.c b/gtk/gtkmultiselection.c index 051d45ae33..40fc3402a9 100644 --- a/gtk/gtkmultiselection.c +++ b/gtk/gtkmultiselection.c @@ -246,21 +246,6 @@ gtk_multi_selection_unselect_callback (GtkSelectionModel *model, return gtk_multi_selection_add_or_remove (model, FALSE, FALSE, callback, data); } -#if 0 -static void -gtk_multi_selection_query_range (GtkSelectionModel *model, - guint position, - guint *start_range, - guint *n_items, - gboolean *selected) -{ - GtkMultiSelection *self = GTK_MULTI_SELECTION (model); - guint upper_bound = g_list_model_get_n_items (self->model); - - gtk_set_find_range (self->selected, position, upper_bound, start_range, n_items, selected); -} -#endif - static void gtk_multi_selection_selection_model_init (GtkSelectionModelInterface *iface) { @@ -273,9 +258,6 @@ gtk_multi_selection_selection_model_init (GtkSelectionModelInterface *iface) iface->unselect_all = gtk_multi_selection_unselect_all; iface->select_callback = gtk_multi_selection_select_callback; iface->unselect_callback = gtk_multi_selection_unselect_callback; -#if 0 - iface->query_range = gtk_multi_selection_query_range; -#endif } G_DEFINE_TYPE_EXTENDED (GtkMultiSelection, gtk_multi_selection, G_TYPE_OBJECT, 0, diff --git a/gtk/gtknoselection.c b/gtk/gtknoselection.c index c3706f2e1c..72ace9a5a5 100644 --- a/gtk/gtknoselection.c +++ b/gtk/gtknoselection.c @@ -21,6 +21,7 @@ #include "gtknoselection.h" +#include "gtkbitset.h" #include "gtkintl.h" #include "gtkselectionmodel.h" @@ -96,25 +97,19 @@ gtk_no_selection_is_selected (GtkSelectionModel *model, return FALSE; } -static void -gtk_no_selection_query_range (GtkSelectionModel *model, - guint position, - guint *start_range, - guint *n_range, - gboolean *selected) +static GtkBitset * +gtk_no_selection_get_selection_in_range (GtkSelectionModel *model, + guint pos, + guint n_items) { - GtkNoSelection *self = GTK_NO_SELECTION (model); - - *start_range = 0; - *n_range = g_list_model_get_n_items (self->model); - *selected = FALSE; + return gtk_bitset_new_empty (); } static void gtk_no_selection_selection_model_init (GtkSelectionModelInterface *iface) { - iface->is_selected = gtk_no_selection_is_selected; - iface->query_range = gtk_no_selection_query_range; + iface->is_selected = gtk_no_selection_is_selected; + iface->get_selection_in_range = gtk_no_selection_get_selection_in_range; } G_DEFINE_TYPE_EXTENDED (GtkNoSelection, gtk_no_selection, G_TYPE_OBJECT, 0, diff --git a/gtk/gtkpropertyselection.c b/gtk/gtkpropertyselection.c index 25fb94846d..2fa311091e 100644 --- a/gtk/gtkpropertyselection.c +++ b/gtk/gtkpropertyselection.c @@ -21,6 +21,7 @@ #include "gtkpropertyselection.h" +#include "gtkbitset.h" #include "gtkintl.h" #include "gtkselectionmodel.h" @@ -275,42 +276,6 @@ gtk_property_selection_unselect_callback (GtkSelectionModel *model, return gtk_property_selection_add_or_remove (model, FALSE, FALSE, callback, data); } -static void -gtk_property_selection_query_range (GtkSelectionModel *model, - guint position, - guint *start_range, - guint *n_items, - gboolean *selected) -{ - GtkPropertySelection *self = GTK_PROPERTY_SELECTION (model); - guint n; - gboolean sel; - guint start, end; - - n = g_list_model_get_n_items (G_LIST_MODEL (self)); - sel = is_selected (self, position); - - start = position; - while (start > 0) - { - if (is_selected (self, start - 1) != sel) - break; - start--; - } - - end = position; - while (end + 1 < n) - { - if (is_selected (self, end + 1) != sel) - break; - end++; - } - - *start_range = start; - *n_items = end - start + 1; - *selected = sel; -} - static void gtk_property_selection_selection_model_init (GtkSelectionModelInterface *iface) { @@ -323,7 +288,6 @@ gtk_property_selection_selection_model_init (GtkSelectionModelInterface *iface) iface->unselect_all = gtk_property_selection_unselect_all; iface->select_callback = gtk_property_selection_select_callback; iface->unselect_callback = gtk_property_selection_unselect_callback; - iface->query_range = gtk_property_selection_query_range; } G_DEFINE_TYPE_EXTENDED (GtkPropertySelection, gtk_property_selection, G_TYPE_OBJECT, 0, diff --git a/gtk/gtkselectionmodel.c b/gtk/gtkselectionmodel.c index 1bd62e810d..24db61f739 100644 --- a/gtk/gtkselectionmodel.c +++ b/gtk/gtkselectionmodel.c @@ -21,6 +21,7 @@ #include "gtkselectionmodel.h" +#include "gtkbitset.h" #include "gtkintl.h" #include "gtkmarshalers.h" @@ -79,7 +80,33 @@ static gboolean gtk_selection_model_default_is_selected (GtkSelectionModel *model, guint position) { - return FALSE; + GtkBitset *bitset; + gboolean selected; + + bitset = gtk_selection_model_get_selection_in_range (model, position, 1); + selected = gtk_bitset_contains (bitset, position); + gtk_bitset_unref (bitset); + + return selected; +} + +static GtkBitset * +gtk_selection_model_default_get_selection_in_range (GtkSelectionModel *model, + guint position, + guint n_items) +{ + GtkBitset *bitset; + guint i; + + bitset = gtk_bitset_new_empty (); + + for (i = position; i < position + n_items; i++) + { + if (gtk_selection_model_is_selected (model, i)) + gtk_bitset_add (bitset, i); + } + + return bitset; } static gboolean @@ -142,31 +169,11 @@ gtk_selection_model_default_unselect_all (GtkSelectionModel *model) return gtk_selection_model_unselect_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL (model))); } -static void -gtk_selection_model_default_query_range (GtkSelectionModel *model, - guint position, - guint *start_range, - guint *n_items, - gboolean *selected) -{ - *start_range = position; - - if (position >= g_list_model_get_n_items (G_LIST_MODEL (model))) - { - *n_items = 0; - *selected = FALSE; - } - else - { - *n_items = 1; - *selected = gtk_selection_model_is_selected (model, position); - } -} - static void gtk_selection_model_default_init (GtkSelectionModelInterface *iface) { iface->is_selected = gtk_selection_model_default_is_selected; + iface->get_selection_in_range = gtk_selection_model_default_get_selection_in_range; iface->select_item = gtk_selection_model_default_select_item; iface->unselect_item = gtk_selection_model_default_unselect_item; iface->select_range = gtk_selection_model_default_select_range; @@ -175,7 +182,6 @@ gtk_selection_model_default_init (GtkSelectionModelInterface *iface) iface->unselect_all = gtk_selection_model_default_unselect_all; iface->select_callback = gtk_selection_model_default_select_callback; iface->unselect_callback = gtk_selection_model_default_unselect_callback; - iface->query_range = gtk_selection_model_default_query_range; /** * GtkSelectionModel::selection-changed @@ -225,6 +231,62 @@ gtk_selection_model_is_selected (GtkSelectionModel *model, return iface->is_selected (model, position); } +/** + * gtk_selection_model_get_selection: + * @model: a #GtkSelectionModel + * + * Gets the set containing all currently selected items in the model. + * + * This function may be slow, so if you are only interested in single item, + * consider using gtk_selection_model_is_selected() or if you are only + * interested in a few consider gtk_selection_model_get_selection_in_range(). + * + * Returns: (transfer full): a #GtkBitset containing all the values currently + * selected in @model. If no items are selected, the bitset is empty. + * The bitset must not be modified. + **/ +GtkBitset * +gtk_selection_model_get_selection (GtkSelectionModel *model) +{ + g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), gtk_bitset_new_empty ()); + + return gtk_selection_model_get_selection_in_range (model, 0, g_list_model_get_n_items (G_LIST_MODEL (model))); +} + +/** + * gtk_selection_model_get_selection_in_range: + * @model: a #GtkSelectionModel + * @position: start of the queired range + * @n_items: number of items in the queried range + * + * Gets a set containing a set where the values in the range [position, + * position + n_items) match the selected state of the items in that range. + * All values outside that range are undefined. + * + * This function is an optimization for gtk_selection_model_get_selection() when + * you are only interested in part of the model's selected state. A common use + * case is in response to the :selection-changed signal. + * + * Returns: A #GtkBitset that matches the selection state for the given state + * with all other values being undefined. + * The bitset must not be modified. + **/ +GtkBitset * +gtk_selection_model_get_selection_in_range (GtkSelectionModel *model, + guint position, + guint n_items) +{ + GtkSelectionModelInterface *iface; + + g_return_val_if_fail (GTK_IS_SELECTION_MODEL (model), gtk_bitset_new_empty ()); + + if (n_items == 0) + return gtk_bitset_new_empty (); + + iface = GTK_SELECTION_MODEL_GET_IFACE (model); + return iface->get_selection_in_range (model, position, n_items); +} + /** * gtk_selection_model_select_item: * @model: a #GtkSelectionModel @@ -383,46 +445,6 @@ gtk_selection_model_unselect_callback (GtkSelectionModel *model, return GTK_SELECTION_MODEL_GET_IFACE (model)->unselect_callback (model, callback, data); } -/** - * gtk_selection_model_query_range: - * @model: a #GtkSelectionModel - * @position: the position inside the range - * @start_range: (out): returns the position of the first element of the range - * @n_items: (out): returns the size of the range - * @selected: (out): returns whether items in @range are selected - * - * This function allows to query the selection status of multiple elements at once. - * It is passed a position and returns a range of elements of uniform selection status. - * - * If @position is greater than the number of items in @model, @n_items is set to 0. - * Otherwise the returned range is guaranteed to include the passed-in position, so - * @n_items will be >= 1. - * - * Positions directly adjacent to the returned range may have the same selection - * status as the returned range. - * - * This is an optimization function to make iterating over a model faster when few - * items are selected. However, it is valid behavior for implementations to use a - * naive implementation that only ever returns a single element. - */ -void -gtk_selection_model_query_range (GtkSelectionModel *model, - guint position, - guint *start_range, - guint *n_items, - gboolean *selected) -{ - GtkSelectionModelInterface *iface; - - g_return_if_fail (GTK_IS_SELECTION_MODEL (model)); - g_return_if_fail (start_range != NULL); - g_return_if_fail (n_items != NULL); - g_return_if_fail (selected != NULL); - - iface = GTK_SELECTION_MODEL_GET_IFACE (model); - return iface->query_range (model, position, start_range, n_items, selected); -} - /** * gtk_selection_model_selection_changed: * @model: a #GtkSelectionModel diff --git a/gtk/gtkselectionmodel.h b/gtk/gtkselectionmodel.h index 55a012e3d6..e48ce20fee 100644 --- a/gtk/gtkselectionmodel.h +++ b/gtk/gtkselectionmodel.h @@ -24,7 +24,7 @@ #error "Only can be included directly." #endif -#include +#include G_BEGIN_DECLS @@ -66,6 +66,9 @@ typedef void (* GtkSelectionCallback) (guint position, /** * GtkSelectionModelInterface: * @is_selected: Return if the item at the given position is selected. + * @get_selection_in_range: Return a bitset with all currently selected + * items in the given range. By default, this function will call + * #GtkSelectionModel::is_selected() on all items in the given range. * @select_item: Select the item in the given position. If the operation * is known to fail, return %FALSE. * @unselect_item: Unselect the item in the given position. If the @@ -81,10 +84,13 @@ typedef void (* GtkSelectionCallback) (guint position, * unsupported or known to fail for all items, return %FALSE. * * The list of virtual functions for the #GtkSelectionModel interface. - * All getter functions are mandatory to implement, but the model does - * not need to implement any functions to support selecting or unselecting - * items. Of course, if the model does not do that, it means that users - * cannot select or unselect items in a list widgets using the model. + * No function must be implemented, but unless #GtkSelectionModel::is_selected() + * is implemented, it will not be possible to select items in the set. + * + * The model does not need to implement any functions to support either + * selecting or unselecting items. Of course, if the model does not do that, + * it means that users cannot select or unselect items in a list widget + * using the model. */ struct _GtkSelectionModelInterface { @@ -94,6 +100,9 @@ struct _GtkSelectionModelInterface /*< public >*/ gboolean (* is_selected) (GtkSelectionModel *model, guint position); + GtkBitset * (* get_selection_in_range) (GtkSelectionModel *model, + guint position, + guint n_items); gboolean (* select_item) (GtkSelectionModel *model, guint position, @@ -116,16 +125,18 @@ struct _GtkSelectionModelInterface gboolean (* unselect_callback) (GtkSelectionModel *model, GtkSelectionCallback callback, gpointer data); - void (* query_range) (GtkSelectionModel *model, - guint position, - guint *start_range, - guint *n_items, - gboolean *selected); }; GDK_AVAILABLE_IN_ALL gboolean gtk_selection_model_is_selected (GtkSelectionModel *model, guint position); +GDK_AVAILABLE_IN_ALL +GtkBitset * gtk_selection_model_get_selection (GtkSelectionModel *model); +GDK_AVAILABLE_IN_ALL +GtkBitset * gtk_selection_model_get_selection_in_range + (GtkSelectionModel *model, + guint position, + guint n_items); GDK_AVAILABLE_IN_ALL gboolean gtk_selection_model_select_item (GtkSelectionModel *model, @@ -158,13 +169,6 @@ gboolean gtk_selection_model_unselect_callback (GtkSelectionMod GtkSelectionCallback callback, gpointer data); -GDK_AVAILABLE_IN_ALL -void gtk_selection_model_query_range (GtkSelectionModel *model, - guint position, - guint *start_range, - guint *n_items, - gboolean *selected); - /* for implementations only */ GDK_AVAILABLE_IN_ALL void gtk_selection_model_selection_changed (GtkSelectionModel *model, diff --git a/gtk/gtksingleselection.c b/gtk/gtksingleselection.c index 5d0172c7b1..bd35aed782 100644 --- a/gtk/gtksingleselection.c +++ b/gtk/gtksingleselection.c @@ -21,6 +21,7 @@ #include "gtksingleselection.h" +#include "gtkbitset.h" #include "gtkintl.h" #include "gtkselectionmodel.h" @@ -110,6 +111,21 @@ gtk_single_selection_is_selected (GtkSelectionModel *model, return self->selected == position; } +static GtkBitset * +gtk_single_selection_get_selection_in_range (GtkSelectionModel *model, + guint position, + guint n_items) +{ + GtkSingleSelection *self = GTK_SINGLE_SELECTION (model); + GtkBitset *result; + + result = gtk_bitset_new_empty (); + if (self->selected != GTK_INVALID_LIST_POSITION) + gtk_bitset_add (result, self->selected); + + return result; +} + static gboolean gtk_single_selection_select_item (GtkSelectionModel *model, guint position, @@ -138,57 +154,13 @@ gtk_single_selection_unselect_item (GtkSelectionModel *model, return TRUE; } -static void -gtk_single_selection_query_range (GtkSelectionModel *model, - guint position, - guint *start_range, - guint *n_range, - gboolean *selected) -{ - GtkSingleSelection *self = GTK_SINGLE_SELECTION (model); - guint n_items; - - n_items = g_list_model_get_n_items (self->model); - - if (position >= n_items) - { - *start_range = position; - *n_range = 0; - *selected = FALSE; - } - else if (self->selected == GTK_INVALID_LIST_POSITION) - { - *start_range = 0; - *n_range = n_items; - *selected = FALSE; - } - else if (position < self->selected) - { - *start_range = 0; - *n_range = self->selected; - *selected = FALSE; - } - else if (position > self->selected) - { - *start_range = self->selected + 1; - *n_range = n_items - *start_range; - *selected = FALSE; - } - else - { - *start_range = self->selected; - *n_range = 1; - *selected = TRUE; - } -} - static void gtk_single_selection_selection_model_init (GtkSelectionModelInterface *iface) { iface->is_selected = gtk_single_selection_is_selected; + iface->get_selection_in_range = gtk_single_selection_get_selection_in_range; iface->select_item = gtk_single_selection_select_item; iface->unselect_item = gtk_single_selection_unselect_item; - iface->query_range = gtk_single_selection_query_range; } G_DEFINE_TYPE_EXTENDED (GtkSingleSelection, gtk_single_selection, G_TYPE_OBJECT, 0, diff --git a/testsuite/gtk/singleselection.c b/testsuite/gtk/singleselection.c index 24de458e1c..81b96e90d0 100644 --- a/testsuite/gtk/singleselection.c +++ b/testsuite/gtk/singleselection.c @@ -593,28 +593,30 @@ test_persistence (void) } static void -check_query_range (GtkSelectionModel *selection) +check_get_selection (GtkSelectionModel *selection) { - guint i, j; - guint position, n_items; - gboolean selected; + GtkBitset *set; + guint i, n_items; - /* check that range always contains position, and has uniform selection */ - for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (selection)); i++) + set = gtk_selection_model_get_selection (selection); + + n_items = g_list_model_get_n_items (G_LIST_MODEL (selection)); + if (n_items == 0) { - gtk_selection_model_query_range (selection, i, &position, &n_items, &selected); - g_assert_cmpint (position, <=, i); - g_assert_cmpint (i, <, position + n_items); - for (j = position; j < position + n_items; j++) - g_assert_true (selected == gtk_selection_model_is_selected (selection, j)); + g_assert_true (gtk_bitset_is_empty (set)); } - - /* check that out-of-range returns the correct invalid values */ - i = MIN (i, g_random_int ()); - gtk_selection_model_query_range (selection, i, &position, &n_items, &selected); - g_assert_cmpint (position, ==, i); - g_assert_cmpint (n_items, ==, 0); - g_assert_true (!selected); + else + { + for (i = 0; i < n_items; i++) + { + g_assert_cmpint (gtk_bitset_contains (set, i), ==, gtk_selection_model_is_selected (selection, i)); + } + + /* check that out-of-range has no bits set */ + g_assert_cmpint (gtk_bitset_get_maximum (set), <, g_list_model_get_n_items (G_LIST_MODEL (selection))); + } + + gtk_bitset_unref (set); } static void @@ -625,16 +627,16 @@ test_query_range (void) store = new_store (1, 5, 1); selection = new_model (store, TRUE, TRUE); - check_query_range (selection); + check_get_selection (selection); gtk_selection_model_unselect_item (selection, 0); - check_query_range (selection); + check_get_selection (selection); gtk_selection_model_select_item (selection, 2, TRUE); - check_query_range (selection); + check_get_selection (selection); gtk_selection_model_select_item (selection, 4, TRUE); - check_query_range (selection); + check_get_selection (selection); ignore_selection_changes (selection); -- 2.30.2